home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 054 (1988-05-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 054 (1988-05-15)(Ossowski, Stefan)(DE)(PD).adf / MRBackup / MRBackup2.0 / MRDates.c < prev    next >
C/C++ Source or Header  |  1988-04-09  |  12KB  |  473 lines

  1.  
  2. /* General routines to provide date support for the DateStamp
  3.  * date format.
  4.  *
  5.  * Author:        Mark R. Rinfret    (mark@unisec.usi.com)
  6.  * Date:        07/18/87
  7.  *
  8.  * This source is released to the public domain by the author, without
  9.  * restrictions.  However, it is requested that you give credit where
  10.  * credit is due and share any bug fixes or enhancements with him.
  11.  *
  12.  * History:        (most recent change first)
  13.  *
  14.  * 12/30/87 -MRR- I experienced some problems with dates past 12/28/87 and
  15.  *                started investigating.  After spending entirely too much
  16.  *                time on the problem, I stole the code from ShowDate in
  17.  *                Rob Peck's book and stuck it in UnpackDS.  I've left my
  18.  *                buggy code intact, but surrounded by conditional compile
  19.  *                brackets which aren't turned on.  The current algorithm
  20.  *                only supports dates back to 03/01/84 while the system
  21.  *                date format begins with 01/01/78.  The current algorithm
  22.  *                is also quite unreadable - too many unexplained constants.
  23.  *
  24.  * 08/20/87 -MRR- Gack!  I wrote this?  In the interests of orthogonality,
  25.  *                I have replaced SetDateStamp with PackDS, the inverse
  26.  *                of UnpackDS.  I have also renamed the package MRDates
  27.  *                to provide a unique name, hopefully relieving conflicts
  28.  *                with other packages providing date/time functions.  The
  29.  *                  UnpackedDS type is now defined in MRDates.h and can
  30.  *                be included by modules which require PackDS and UnpackDS.
  31.  */
  32.  
  33. /* The following #define MUST be set to inhibit certain declarations in
  34.  * the include file MRDates.h:
  35.  */
  36.  
  37. #define MRDATES
  38.  
  39. #include <libraries/dos.h>
  40. #include <exec/memory.h>
  41. #include <ctype.h>
  42. #include <functions.h>
  43. #include ":src/lib/MRDates.h"
  44.  
  45. /* #define DEBUG */
  46.  
  47.  
  48. char *daynames[] = {
  49.     "Sunday", "Monday", "Tuesday", "Wednesday", 
  50.     "Thursday", "Friday", "Saturday"
  51.     };
  52.  
  53. USHORT monthDays[12] =  {    0,        /* JAN */
  54.                             31,        /* FEB */
  55.                             59,        /* MAR */
  56.                             90,        /* APR */
  57.                             120,    /* MAY */
  58.                             151,    /* JUN */
  59.                             181,    /* JUL */
  60.                             212,    /* AUG */
  61.                             243,    /* SEP */
  62.                             273,    /* OCT */
  63.                             304,    /* NOV */
  64.                             334     /* DEC */
  65.                             };
  66.  
  67. char *monthnames[12] = {
  68.     "January", "February", "March", "April", "May", "June",
  69.     "July", "August", "September", "October", "November", "December"
  70.     };
  71.  
  72. /* Compare two DateStamp values.
  73.  * Called with:
  74.  *        d1,d2:        pointers to DateStamp structs
  75.  * 
  76.  * Returns:
  77.  *        < 0 => d1 < d2
  78.  *          0 => d1 == d2
  79.  *        > 0 => d1 > d2
  80.  *
  81.  * Note:
  82.  *        This routine makes an assumption about the DateStamp structure,
  83.  *        specifically that it can be viewed as an array of 3 long integers
  84.  *        in days, minutes and ticks order.
  85.  */
  86.  
  87. int 
  88. CompareDS(d1, d2)
  89.     long *d1, *d2;
  90. {
  91.     USHORT i;
  92.     long compare;
  93.  
  94.     for (i = 0; i < 3; ++i) {
  95.         if (compare = (d1[i] - d2[i])) {
  96.             if (compare < 0) return -1;
  97.             return 1;
  98.         }
  99.     }
  100.     return 0;                        /* dates match */
  101. }
  102.  
  103. /* Convert a DateStamp to a formatted string.
  104.  * Called with:
  105.  *        fmt:    format string
  106.  *            The format of the format string is very similar to that
  107.  *            for printf, with the exception that the following letters
  108.  *            have special significance:
  109.  *                y => year minus 1900
  110.  *                Y => full year value
  111.  *                m => month value as integer
  112.  *                M => month name
  113.  *                d => day of month (1..31)
  114.  *                D => day name ("Monday".."Sunday")
  115.  *                h => hour in twenty-four hour notation
  116.  *                H => hour in twelve hour notation
  117.  *                i => 12 hour indicator for H notation (AM or PM)
  118.  *                I => same as i
  119.  *                n => minutes    (sorry...conflict with m = months)
  120.  *                N => same as n
  121.  *                s => seconds
  122.  *                S => same as s
  123.  *
  124.  *            All other characters are passed through as part of the normal
  125.  *            formatting process.  The following are some examples with
  126.  *            Saturday, July 18, 1987, 13:53 as an input date:
  127.  *
  128.  *                "%y/%m/%d"            => 87/7/18
  129.  *                "%02m/%02d/%2y"        => 07/18/87
  130.  *                "%D, %M %d, %Y"        => Saturday, July 18, 1987
  131.  *                "%02H:%02m i"        => 01:53 PM
  132.  *                "Time now: %h%m"    => Time now: 13:53
  133.  *
  134.  *        str:    string to write date on
  135.  *        d:        pointer to DateStamp structure
  136.  *        
  137.  */
  138. void
  139. DS2Str(str,fmt,d)
  140.     char *str, *fmt; struct DateStamp *d;
  141. {
  142.     UnpackedDS date;
  143.     char fc,*fs,*out;
  144.     USHORT ivalue;
  145.     char new_fmt[256];            /* make it big to be "safe" */
  146.     USHORT new_fmt_lng;
  147.     char *svalue;
  148.  
  149.     UnpackDS(d, &date);            /* convert DateStamp to unpacked format */
  150.  
  151.     *str = '\0';                /* insure output is empty */
  152.     out = str;
  153.     fs = fmt;                    /* make copy of format string pointer */
  154.  
  155.     while (fc = *fs++) {        /* get format characters */
  156.         if (fc == '%') {        /* formatting meta-character? */
  157.             new_fmt_lng = 0;
  158.             new_fmt[new_fmt_lng++] = fc;
  159.             /* copy width information */
  160.             while (isdigit(fc = *fs++) || fc == '-')
  161.                 new_fmt[new_fmt_lng++] = fc;
  162.  
  163.             switch (fc) {        /* what are we trying to do? */
  164.             case 'y':            /* year - 1980 */
  165.                 ivalue = date.year - 1900;
  166. write_int:
  167.                 new_fmt[new_fmt_lng++] = 'd';
  168.                 new_fmt[new_fmt_lng] = '\0';
  169.                 sprintf(out,new_fmt,ivalue);
  170.                 out = str + strlen(str);
  171.                 break;
  172.             case 'Y':            /* full year value */
  173.                 ivalue = date.year;
  174.                 goto write_int;
  175.  
  176.             case 'm':            /* month */
  177.                 ivalue = date.month;
  178.                 goto write_int;
  179.  
  180.             case 'M':            /* month name */
  181.                 svalue = monthnames[date.month - 1];
  182. write_str:
  183.                 new_fmt[new_fmt_lng++] = 's';
  184.                 new_fmt[new_fmt_lng] = '\0';
  185.                 sprintf(out,new_fmt,svalue);
  186.                 out = str + strlen(str);
  187.                 break;
  188.  
  189.             case 'd':            /* day */
  190.                 ivalue = date.day;
  191.                 goto write_int;
  192.  
  193.             case 'D':            /* day name */
  194.                 svalue = daynames[d->ds_Days % 7];
  195.                 goto write_str;
  196.  
  197.             case 'h':            /* hour */
  198.                 ivalue = date.hour;
  199.                 goto write_int;
  200.  
  201.             case 'H':            /* hour in 12 hour notation */
  202.                 ivalue = date.hour;
  203.                 if (ivalue >= 12) ivalue -= 12;
  204.                 goto write_int;
  205.  
  206.             case 'i':            /* AM/PM indicator */
  207.             case 'I':
  208.                 if (date.hour >= 12)
  209.                     svalue = "PM";
  210.                 else
  211.                     svalue = "AM";
  212.                 goto write_str;
  213.  
  214.             case 'n':            /* minutes */
  215.             case 'N':
  216.                 ivalue = date.minute;
  217.                 goto write_int;
  218.  
  219.             case 's':            /* seconds */
  220.             case 'S':
  221.                 ivalue = date.second;
  222.                 goto write_int;
  223.  
  224.             default:
  225.                 /* We are in deep caca - don't know what to do with this
  226.                  * format character.  Copy the raw format string to the
  227.                  * output as debugging information.
  228.                  */
  229.                 new_fmt[new_fmt_lng++] = fc;
  230.                 new_fmt[new_fmt_lng] = '\0';
  231.                 strcat(out, new_fmt);
  232.                 out = out + strlen(out);    /* advance string pointer */
  233.                 break;
  234.             }
  235.         }
  236.         else
  237.             *out++ = fc;        /* copy literal character */
  238.     }
  239.     *out = '\0';                /* terminating null */
  240. }
  241.  
  242. /* Convert a string to a DateStamp.
  243.  * Called with:
  244.  *        str:    string containing date in MM/DD/YY format        
  245.  *        d:        pointer to DateStamp structure
  246.  * Returns:
  247.  *        status code (0 => success, 1 => failure)
  248.  */
  249.  
  250. int
  251. Str2DS(str, d)
  252.     char *str; struct DateStamp *d;
  253. {
  254.     register char c;
  255.     int count;
  256.     int i, item;
  257.     UnpackedDS upd;                /* unpacked DateStamp */
  258.     char *s;
  259.  
  260.     int values[3];
  261.     int value;
  262.     
  263.  
  264.     s = str;
  265.     for (item = 0; item < 2; ++item) {    /* item = date, then time */
  266.         for (i = 0; i < 3; ++i) values[i] = 0;
  267.         count = 0;
  268.         while (c = *s++) {            /* get date value */
  269.             if (c <= ' ') 
  270.                 break;
  271.  
  272.             if (isdigit(c)) {
  273.                 value = 0;
  274.                 do {
  275.                     value = value*10 + c - '0';
  276.                     c = *s++;
  277.                 } while (isdigit(c));
  278.                 if (count == 3) {
  279.     bad_value:
  280. #ifdef DEBUG
  281.                     puts("Error in date-time format.\n");
  282.                     printf("at %s: values(%d) = %d, %d, %d\n",
  283.                         s, count, values[0], values[1], values[2]);
  284. #endif
  285.                     return 1;
  286.                 }
  287.                 values[count++] = value;
  288.                 if (c <= ' ')
  289.                     break;
  290.             }
  291.         }                            /* end while */
  292.         if (item) {                    /* getting time? */
  293.             upd.hour = values[0];
  294.             upd.minute = values[1];
  295.             upd.second = values[2];
  296.         }
  297.         else {                        /* getting date? */
  298.  
  299. /* It's OK to have a null date string, but it's not OK to specify only
  300.  * 1 or 2 of the date components.
  301.  */
  302.             if (count && count != 3)
  303.                 goto bad_value;
  304.             upd.month = values[0];
  305.             upd.day = values[1];
  306.             upd.year = values[2];
  307.         }
  308.     }                                /* end for */
  309.     PackDS(d,&upd);
  310.     return 0;
  311. }
  312.  
  313.  
  314. /* Set a DateStamp structure, given the date/time components.
  315.  * Called with:
  316.  *        d:            pointer to DateStamp
  317.  *      upd:        pointer to UnpackedDS
  318.  */
  319. PackDS(d,upd)
  320.     struct DateStamp *d; UnpackedDS *upd;
  321. {
  322.     USHORT leapyear;
  323.     short year,month,day,hour,minute,second;
  324.  
  325.     year = upd->year;            /* copy date components to locals */
  326.     month = upd->month;
  327.     day = upd->day;
  328.     hour = upd->hour;
  329.     minute = upd->minute;
  330.     second = upd->second;
  331.  
  332.     if (year > 1900)
  333.         year = year - 1900;
  334.  
  335.     leapyear = (year % 4 ? 0 : 1);
  336.  
  337.     year = year - 78;
  338.     if (month < 1 || month > 12)    /* somebody goofed? */
  339.         month = 1;
  340.  
  341.     day = day - 1 + monthDays[month-1];
  342.     if (leapyear && (month > 2))
  343.         ++day;
  344.  
  345.     d->ds_Days = year * 365 + (year + 1) / 4 + day;
  346.     d->ds_Minute = hour * 60 + minute;
  347.     d->ds_Tick = second * TICKS_PER_SECOND;
  348. }
  349.  
  350. /* Unpack a DateStamp structure into an UnpackedDS structure. 
  351.  * Called with:
  352.  *        ds:        pointer to DateStamp structure
  353.  *        du:        pointer to UnpackedDS structure
  354.  */
  355. UnpackDS(ds, du)
  356.     struct DateStamp *ds; UnpackedDS *du;
  357. {
  358. #ifdef OLDCODE
  359.     USHORT i, leap, leapYears, temp, testValue, year;
  360.  
  361.     /* Compute the year as an offset from 1978.  This is an integer
  362.      * approach to "year = days / 365.25" (since there are 365.25 days
  363.      * in a year).
  364.      */
  365.  
  366.     year = ( ((ds->ds_Days + 1) * 100) / 36525);
  367.     leapYears = (year + 1) / 4;
  368.  
  369.     du->year = year + 1978;
  370.  
  371. #ifdef DEBUG
  372.     printf("\nDays == %ld, Years == %d, Leapyears == %d\n", 
  373.             ds->ds_Days, year, leapYears);
  374. #endif
  375.  
  376.     /* Is current year a leapyear? */
  377.     leap = ( (year % 4) == 0); 
  378.  
  379.     /* Get the days into the year. */
  380.     temp = (ds->ds_Days - (year * 365) - leapYears);
  381.  
  382.     /* Find the month. */
  383.  
  384.     du->month = 0;
  385.     du->day = 0;
  386.     for (i = 11; i >= 0; --i) {
  387.         testValue = monthDays[i];
  388.         if (i >= 2) testValue += leap;
  389.         if (temp >= testValue) {
  390.             du->month = i + 1;
  391.             du->day = temp - testValue + 1;
  392.             break;
  393.         }
  394.     }
  395. #else
  396.     long n; int m,d,y;
  397.  
  398.     n = ds->ds_Days - 2251;
  399.     y = (4 * n + 3) / 1461;
  400.     n -= 1461 * (long) y / 4;
  401.     y += 1984;
  402.     m = (5 * n + 2) / 153;
  403.     d = n - (153 * m + 2) / 5 + 1;
  404.     m += 3;
  405.     if (m > 12) {
  406.         ++y;
  407.         m -= 12;
  408.     }
  409.     du->year = y;
  410.     du->month = m;
  411.     du->day = d;
  412. #endif
  413.     du->hour = ds->ds_Minute / 60;
  414.     du->minute = ds->ds_Minute % 60;
  415.     du->second = ds->ds_Tick / TICKS_PER_SECOND;
  416.  
  417. }
  418.  
  419.  
  420. #ifdef DEBUG
  421. main()
  422. {
  423.     int compflag;
  424.     char datestr[81], instr[81];
  425.     struct DateStamp *ds, *now;
  426.     UnpackedDS du;
  427.  
  428.     now = (struct DateStamp *) 
  429.         AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
  430.  
  431.     ds = (struct DateStamp *) 
  432.         AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
  433.  
  434.     puts("Enter a date string and I will convert it.  To quit, hit RETURN");
  435.     while (1) {
  436.         DateStamp(now);
  437.         UnpackDS(now, &du);
  438.  
  439.         printf("\nCurrent date and time: %02d/%02d/%02d %02d:%02d:%02d\n",
  440.             du.month,du.day,du.year,du.hour,du.minute,du.second);
  441.  
  442.         puts("\nEnter the date [and time]:");
  443.         gets(instr);
  444.         if (*instr == '\0') break;
  445.         if (Str2DS(instr,ds))
  446.             puts("Error encountered in input string");
  447.         else {
  448.             DS2Str(datestr, "%02m/%02d/%02y %02h:%02n:%02s", ds);
  449.             puts(datestr);
  450.  
  451.             DS2Str(datestr, "%D, %M %d, %Y", ds);
  452.             puts(datestr);
  453.  
  454.             DS2Str(datestr, "The time entered is %02H:%02N %i", ds);
  455.             puts(datestr);
  456.  
  457.             compflag = CompareDS(ds,now);
  458.             printf("The date input is ");
  459.             if (compflag < 0)
  460.                 printf("earlier than");
  461.             else if (compflag == 0)
  462.                 printf("the same as");
  463.             else
  464.                 printf("later than");
  465.             puts(" the current date.");
  466.         }
  467.     }
  468.  
  469.     FreeMem(ds, (long) sizeof(struct DateStamp));
  470.     FreeMem(now, (long) sizeof(struct DateStamp));
  471. }
  472. #endif
  473.